//=============================================================================

#ifndef AMODEL_H
  #define AMODEL_H

//=============================================================================

#include "aSurface.h"
#include "aSkeleton.h"

//=============================================================================

enum amlRet
{
  MOD_DONE = -128,
  MOD_NULLED_FILE_PATH,
  MOD_CANT_OPEN_MODEL_FILE_FOR_READING,
  MOD_WRONG_MODEL_FILE_FORMAT,
  MOD_ALREADY_HAS_THIS_ANIMATION,
  MOD_NO_GEOMETRY_DATA,
  MOD_CANT_OPEN_ANIMATION_FILE_FOR_READING,
  MOD_BAD_ANIMATION_NAME,
  MOD_NO_SKELETON,
  MOD_NO_SUCH_ANIMATION,
  MOD_ANIMATION_ALREADY_ON,
  MOD_ANIMATION_STARTED,
  MOD_COL_BAD_DATA_POINTER,
  MOD_COL_BAD_DATA_VOLUME,
  MOD_COL_NO_SKEL_JOINTS_DATA
};

//=============================================================================

class aPlayAnimation
{
  public:
    aPlayAnimation()
    {
      loop = 0;
      pause = 0;
      currentFrame = 0;
    }

  public:
    aString name;
    bool loop;
    bool pause;
    unsigned int framesCount;
    unsigned int currentFrame;
};

//=============================================================================

class aModel : public aSurface
{
  public:
      inline void amCalculateJoints()                                             {skel.asCalculateJoints();}
      inline void amResetVertexesToNULL()                                         {memset(currentVertexes, 0, sizeof(float)*vertexesCount*3);}
      inline void amResetVertexesToBind()                                         {memcpy(currentVertexes, vertexes, sizeof(float)*vertexesCount*3);}
      inline void amRemoveSkeletonData()                                          {skel.asRemoveSkeletonData();}
      inline void amRemoveAnimationsData()                                        {hasAnimations.alRemoveItems(); playingAnimations.alRemoveItems();}
      inline size_t amGetSkeletonDataVolume()const                                {return skel.asGetDataVolume();}
      inline asnRet amCollectSkeletonData(void* data, size_t wholeSize)const      {return skel.asCollectData(data, wholeSize);}
      inline asnRet amAbsorbSkeletonData(char* data, int jCount)                  {return skel.asFixTheBones(data, jCount);}
      inline asnRet amAbsorbAnimationData(char* data)                             {return skel.asAbsorbAnimations(data, hasAnimations);}
      inline int amGetJointsCount()const                                          {return skel.pubJoints.alGetCount();}
      inline asnRet amLoadSkeleton(const aString& path, unsigned int vCount)      {return skel.asLoadSkeleton(path, vCount);}

    aModel();
      void asDrawSurface()const;
      void asSpawnMemory(unsigned int tCount);
      amlRet amLoadModel(const aString& path);
      amlRet amLoadAnimation(const aString& path, const aString& name);
      amlRet amPlayAnimation(const aString& name, bool loop);
      unsigned int amGetAnimationFramesCount(const aString& name);
      bool amHasAnimation(const aString& name);
      unsigned int amPauseAnimation(const aString& name);
      void amSetAnimationFrame(const aString& name, unsigned int frame);
      bool amIsAnimationPaused(const aString& name);
      unsigned int amGetAnimationFrame(const aString& name);
      void amGetJointsNames(aList<aString>& namesList);
      size_t amGetAnimationDataVolume()const;
      amlRet amCollectAnimationsData(void* data, size_t wholeSize)const;
      void asRemoveSurfaceData();
      void amDestroyModel();
      void amAnimateModel();
    ~aModel();

  private:
      void amCalculateVertexes();
      void asDrawNormals()const;
      aItem<aPlayAnimation>* amGetAnimationByName(const aString& name);

  public:
    bool drawSkeleton;
    bool drawJointsAxis;
    aList<aString> hasAnimations;

  private:
    float* currentVertexes;
    aSkeleton skel;
    aList<aPlayAnimation> playingAnimations;
    unsigned long animationFps;
    unsigned long animationOffset;
    unsigned int framesInterval;
    DWORD lastFrameTime;
    static const size_t magicSize = sizeof(float)*aJoint::matrixSize;
};

//=============================================================================

#endif

//=============================================================================
